﻿using System;
using System.IO;
using System.Text;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml;
using System.Threading;

namespace NWT
{
	/// <summary>
	/// TrafficCounter
	/// </summary>
	public class TrafficCounter
	{
		/// <summary>
		/// Notification
		/// </summary>
		public event EventHandler AmountChanged;

		/// <summary>
		/// Traffic amount
		/// </summary>
		protected object amount = (long)0;

		/// <summary>
		/// Reset counter
		/// </summary>
		public void Reset()
		{
			Interlocked.Exchange(ref amount, (long)0);
			if (AmountChanged != null)
				AmountChanged(this, EventArgs.Empty);
		}

		/// <summary>
		/// Add new traffic amount
		/// </summary>
		/// <param name="amount"></param>
		public void Add(long newAmount)
		{
			lock (amount)
			{
				amount = (long)amount + newAmount;
			}
			if (AmountChanged != null)
				AmountChanged(this, EventArgs.Empty);
		}

		/// <summary>
		/// Traffic amount
		/// </summary>
		public long Amount
		{
			get
			{
				lock (amount)
				{
					return (long)amount;
				}
			}
			set
			{
				lock (amount)
				{
					if ((long)amount != value)
					{
						amount = value;
						if (AmountChanged != null)
							AmountChanged(this, EventArgs.Empty);
					}
				}
			}
		}
	}

	/// <summary>
	/// CustomHeaderExtension
	/// </summary>
	public class CustomHeaderExtension : System.Web.Services.Protocols.SoapExtension
	{
		Stream oldStream;
		Stream newStream;
		public static TrafficCounter SoapTrafficCounter = new TrafficCounter();

		/// <summary>
		/// Constructor
		/// </summary>
		public CustomHeaderExtension()
		{
		}

		/// <summary>
		/// GetInitializer
		/// </summary>
		/// <param name="methodInfo"></param>
		/// <param name="attribute"></param>
		/// <returns></returns>
		public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
		{
			return attribute;
		}

		/// <summary>
		/// Get the Type
		/// </summary>
		/// <param name="t"></param>
		/// <returns></returns>
		public override object GetInitializer(Type t)
		{
			return typeof(CustomHeaderExtension);
		}

		/// <summary>
		/// Get the CompressionExtensionAttribute
		/// </summary>
		/// <param name="initializer"></param>
		public override void Initialize(object initializer)
		{
			CustomHeaderExtensionAttribute attribute = (CustomHeaderExtensionAttribute)initializer;
			return;
		}

		// Process the SOAP Message
		public override void ProcessMessage(SoapMessage message)
		{
			// Check for the various SOAP Message Stages 
			switch (message.Stage)
			{

				case SoapMessageStage.BeforeSerialize:
					break;

				case SoapMessageStage.AfterSerialize:
					AfterSerialize();
					break;

				case SoapMessageStage.BeforeDeserialize:
					BeforeDeserialize();
					break;

				case SoapMessageStage.AfterDeserialize:
					break;
			}
		}


		/// <summary>
		/// Gives us the ability to get hold of the RAW SOAP message
		/// </summary>
		/// <param name="stream"></param>
		/// <returns></returns>
		public override Stream ChainStream(Stream stream)
		{
			oldStream = stream;
			newStream = new MemoryStream();
			return newStream;
		}


		// Utility method to copy streams
		void Copy(Stream from, Stream to)
		{
			TextReader reader = new StreamReader(from);
			TextWriter writer = new StreamWriter(to);
			writer.WriteLine(reader.ReadToEnd());
			writer.Flush();
		}

		//
		private void AfterSerialize()
		{
			newStream.Position = 0;
			SoapTrafficCounter.Add(newStream.Length);
			// Copy the streams
			Copy(newStream, oldStream);
			newStream.Position = 0;
		}

		//
		private void BeforeDeserialize()
		{
			newStream.Position = 0;
			Copy(oldStream, newStream);
			SoapTrafficCounter.Add(newStream.Length);
			// Copy the streams
			newStream.Position = 0;
		}
	}

	[AttributeUsage(AttributeTargets.Method)]
	public class CustomHeaderExtensionAttribute : SoapExtensionAttribute
	{
		/// <summary>
		/// Priority
		/// </summary>
		private int priority;

		/// <summary>
		/// Override the base class properties
		/// </summary>
		public override Type ExtensionType
		{
			get { return typeof(CustomHeaderExtension); }
		}

		/// <summary>
		/// Priority
		/// </summary>
		public override int Priority
		{
			get { return priority; }
			set { priority = value; }
		}
	}
}
